fix(gate-53): join src/registry.js — a manifest ref and its registration (#238) - #250
Merged
Merged
Conversation
…ion (#238) gate-53 never read src/registry.js, so a manifest component ref and its registration were never cross-checked and BOTH directions were silent. That blind spot shipped larpingapp#286: `EventRoster` was registered, resolvable, and named by no manifest position, so the event check-in surface had no entry point. It was unreachable UI long enough for its openspec task to be ticked over it, and the two gates that exist to catch manifest cross-reference defects — 22 and 53 — both reported PASS the whole time. The old comment declined the registry as "app code, not statically checkable". It is app code, but it is not opaque: a fixed-shape ES module whose top-level `export default { … }` keys are its public surface. We cannot require() it (it pulls in .vue SFCs), but the keys extract with brace-depth tracking — which is how the app-local test in larpingapp#288 already does it. DIRECTIONS AND SEVERITIES 2 → FAIL. A manifest `component` naming no registry key renders NOTHING. CnObjectSidebar.resolveTabComponent() falls through and the tab comes up blank. That is gate-14 route-reachability one layer up: unambiguously broken, so it blocks. 1 → WARN. A registered component no manifest position names is either a component that should be wired or one that should be deleted. The gate cannot know which, so it reports rather than prescribes — the same "zero callers has two opposite fixes" property that governs gate-57. ACCEPTANCE — larpingapp#286, both directions, against the real repo as shipped today (the #286 fix is in place) EventRoster NOT flagged Check-in tab's `component` removed WARN, names EventRoster Check-in tab renamed to a component nobody registers ERROR at /pages/17/config/sidebar/tabs/0/component, exit 1 FALSE-POSITIVE CONTROLS, each pinned by a test that a mutation breaks: Cn* names resolve from nextcloud-vue and are exempt; kind:'modal' entries are not required to have a manifest position (open-modal is runtime-resolved and gate (b) already warns); metadata-only entries with no kind are not surfaces; a COMMENTED-OUT registration does not count as a registration; and an app with no src/registry.js skips check (f) entirely. BLAST RADIUS — measured, repos at origin/development, before vs after portaliq 0→0 doriath 0→0 openconnector 0→0 larpingapp 0→0 procest 1→1 (its exit 1 is the pre-existing removals-invariant check, not this one — zero registry-crossref errors) No verdict changes anywhere. Two new WARNs, both genuine orphans: portaliq `CustomExample` (kind page) and larpingapp `ObjectDetail` (kind section), neither named by any manifest position. 13 new assertions over 3 new fixtures. Mutation-checked: disabling direction 2 fails 4, disabling direction 1 fails 2, dropping comment-stripping fails 2, removing the Cn* exemption fails 9, and inverting direction 1 to a FAIL fails 4.
rubenvdlinde
pushed a commit
that referenced
this pull request
Aug 8, 2026
rubenvdlinde
added a commit
that referenced
this pull request
Aug 8, 2026
…follow-up) (#260) I measured the blast radius of #250 on five repos, found no new blocking findings, and shipped. Five repos was not the fleet. A full sweep of all 20 afterwards found 38 new ERROR findings across five OTHER repos, and 34 of them were FALSE. Two causes, both a registration the parser could not see. 1. QUOTED, HYPHENATED KEYS — 25 false FAILs on hermiq. The matcher shared one character class between quoted and bare keys: /(?:^|[,{\s])(?:['"]?)([A-Za-z_$][\w$]*)(?:['"]?)\s*:/g `[\w$]*` excludes `-`, so `'agent-form'` captured `agent` and stopped at the hyphen. Every hyphenated registration was invisible, and every manifest reference to one — `agent-skills`, `agent-run-history`, `agent-tool-governance` — was reported as naming a component nobody registers. Quoted and bare keys are now separate alternatives with different classes. 2. src/customComponents.js — 9 false FAILs on softwarecatalog, 1 on hermiq. It is the SECOND registration source, and the tell was in the finding message I wrote myself: the runtime error it quotes says "not found in registry OR customComponents". Every app's own customComponents.js documents the resolution order in its header. I quoted the fallback and did not implement it. A component resolvable by EITHER route now resolves. MEASURED, all 20 repos at origin/development, before vs after this commit: hermiq 25 ERROR -> 0 softwarecatalog 9 ERROR -> 0 decidesk 1 ERROR -> 1 scholiq 1 ERROR -> 1 shillinq 2 ERROR -> 2 all others 0 ERROR -> 0 The 4 survivors are true positives, each verified by hand against the app's own wiring — App.vue passes only `:registry` in decidesk and scholiq, so a component absent from it renders nothing: decidesk MotionIntegrations — MotionIntegrations.vue exists, registered nowhere, named by pages[].component scholiq OrderPaymentPanel — same shape shillinq ImportWizard — NO .vue file anywhere in src/, named by a manifest.d fragment shillinq StockLedgerTrace — same New fixture registry-dialects covering both dialects plus the control that keeps the exemption from becoming an amnesty: NotAnywherePanel is in neither file and still FAILS. 5 new assertions. Mutations, each asserting it applied before writing: reverting the regex fails 3, removing the customComponents source fails 2, disabling direction 2 fails 6. Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #238.
Cause
gate-53 never read
src/registry.js, so a manifest component ref and its registration were never cross-checked — and both directions were silent. That blind spot shipped ConductionNL/larpingapp#286:EventRosterwas registered, resolvable, and named by no manifest position, so the event check-in surface had no entry point. It was unreachable UI long enough for its openspec task to be ticked over it, and the two gates that exist to catch manifest cross-reference defects — 22 and 53 — both reported PASS the whole time.The old comment declined the registry wholesale: "the modal registry is app code (src/registry.js et al.) the gate cannot statically parse". It is app code, but it is not opaque — a fixed-shape ES module whose top-level
export default { … }keys are its public surface. We cannotrequire()it (it pulls in.vueSFCs), but the keys extract with brace-depth tracking, which is exactly how the app-local test in larpingapp#288 already does it.Directions and severities
resolveTabComponent()falls through and the tab renders nothing. gate-14 route-reachability one layer up: unambiguously broken.Acceptance — larpingapp#286, both directions, against the real repo
origin/developmentas shipped today (the #286 fix is in place)EventRosternot flaggedcomponentremoved — #286 exactly as it shippedEventRosterThisComponentDoesNotExistAnywhere— issue #238's own control/pages/17/config/sidebar/tabs/0/component, exit 1False-positive controls — each pinned by a test a mutation breaks
Widening this check would fail every well-formed manifest in the fleet, so the exemptions are tested, not assumed:
Cn*names resolve from nextcloud-vue, not the app registry — exempt.kind: 'modal'entries are not required to have a manifest position (open-modal is runtime-resolved; gate (b) already WARNs).kindare not renderable surfaces.src/registry.jsskips check (f) entirely.Blast radius — measured, repos at
origin/developmentNo verdict changes anywhere. procest's exit 1 is the pre-existing
removals-invariantcheck, not this one.Two new WARNs, both genuine orphans: portaliq
CustomExample(kind page) and larpingappObjectDetail(kind section), neither named by any manifest position.Tests — 13 new assertions over 3 new fixtures
registry-wired/registry-orphan/registry-missing. The wired fixture is the control: a check that only ever fires is as useless as one that never does.Mutation results:
Cn*exemption removedbash hydra-gates/tests/run-helper-suites.sh→ 27 passed, 0 failed, 2 pre-existing quarantines. The existinggood/brokenfixture assertions (includingexactly 5 error findings — none missed, none extra) are untouched: neither ships asrc/registry.js.Not done here
open-modalaction targets are still WARNed as runtime-resolved. Now that the registry parses, those could be resolved too — but modal targets are not consistently registry-keyed across the fleet, so that is a separate change with its own blast-radius measurement.